#include "ScriptSystem.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#pragma comment(lib,"lua51.lib")
#pragma comment(lib,"lua5.1.lib")

//////////////////////////////////////////////////////////////////////////
void CheckType(const ScriptEntity *se, int idx)
{
	printf("filed\'s type: %s\n", lua_typename(se->m_L, lua_type(se->m_L, idx)));
}
//////////////////////////////////////////////////////////////////////////


bool SetCurrentTable(const ScriptEntity *se, const char *tablename)
{
	int top = lua_gettop(se->m_L); 
	lua_getglobal(se->m_L, tablename);
	if (!lua_istable(se->m_L, -1))
	{
		printf("%s is not a valid table",tablename);
		lua_settop (se->m_L, top); 
		return false;
	}
	return true;
}
double GetTableNumber(const ScriptEntity *se,const char *fieldname)
{
	if(!lua_istable(se->m_L, -1))
	{
		printf("no table been pushed.\n");
		return 0;
	}
	int top = lua_gettop(se->m_L); 
	double result;
	lua_pushstring(se->m_L, fieldname);
	lua_gettable(se->m_L, -2);
	if (!lua_isnumber(se->m_L, -1))
	{
		printf("'%s' not a number.\n",fieldname);
		CheckType(se,-1);
		lua_settop (se->m_L, top); 
		return 0;
	}
	result = lua_tonumber(se->m_L, -1);
	lua_settop (se->m_L, top);
	return result;
}
bool GetTableBoolean(const ScriptEntity *se, const char *fieldname)
{
	if(!lua_istable(se->m_L, -1))
	{
		printf("no table been pushed.\n");
		return false;
	}

	int top = lua_gettop(se->m_L); 
	bool result;
	lua_pushstring(se->m_L, fieldname);
	lua_gettable(se->m_L, -2);
	if (!lua_isboolean(se->m_L, -1))
	{
		printf("'%s' not a boolean.\n",fieldname);
		CheckType(se,-1);
		lua_settop (se->m_L, top); 
		return 0;
	}
	result = lua_toboolean(se->m_L, -1) != 0? true:false;
	lua_settop (se->m_L, top);
	return result;
}
const char* GetTableString(const ScriptEntity *se, const char *fieldname)
{
	if(!lua_istable(se->m_L, -1))
	{
		printf("no table been pushed.\n");
		return 0;
	}
	int top = lua_gettop(se->m_L);
	lua_pushstring(se->m_L, fieldname);
	lua_gettable(se->m_L, -2);
	if (!lua_isstring(se->m_L, -1))
	{
		printf("invalid fieldname %s",fieldname);
		lua_settop (se->m_L, top); 
		return NULL;
	}
	const char* tmp;
	char* result;
	tmp = lua_tostring(se->m_L, -1);
	int len = strlen(tmp);
	result = new char[len + 1];
	strcpy(result,tmp);
	lua_settop (se->m_L, top); 
	return result;
}

double GetGlobalNumber(const ScriptEntity *se, const char *varname)
{
	int top = lua_gettop (se->m_L); 
	lua_getglobal(se->m_L,varname);
	if (!lua_isnumber(se->m_L, -1))
	{
		printf("%s is not a valid number",varname);
		lua_settop (se->m_L, top); 
		return 0;
	}
	double result = lua_tonumber(se->m_L, -1);
	lua_settop (se->m_L, top); 
	return result;
}

const char* GetGlobalString(const ScriptEntity *se, const char *varname)
{
	int top = lua_gettop (se->m_L); 
	lua_getglobal(se->m_L,varname);
	if (!lua_isstring(se->m_L, -1))
	{
		printf("invalid fieldname %s",varname);
		lua_settop (se->m_L, top); 
		return NULL;
	}
	const char* tmp;
	char* result;
	tmp = lua_tostring(se->m_L, -1);
	int len = strlen(tmp);
	result = new char[len + 1];
	strcpy(result,tmp);
	lua_settop (se->m_L, top); 
	return result;
}
bool GetGlobalBoolean(const ScriptEntity *se, const char *varname)
{
	int top = lua_gettop (se->m_L); 
	lua_getglobal(se->m_L,varname);
	
	if (!lua_isboolean(se->m_L, -1))
	{
		printf("'%s' not a boolean.\n",varname);
		CheckType(se,-1);
		lua_settop (se->m_L, top); 
		return 0;
	}
	bool result;
	result = lua_toboolean(se->m_L, -1) != 0? true:false;
	lua_settop (se->m_L, top);
	return result;
}


//////////////////////////////////////////////////////////////////////////

bool CallScriptFunc(const ScriptEntity *se, const char *funcname, char * paraformat,...)
{

	lua_getglobal(se->m_L,funcname);
	if (!lua_isfunction(se->m_L,-1))
	{
		printf("\'%s\' is not a function.\n",funcname);
		return false;
	}
	int paranum = 0;
	if(paraformat != 0)
	{
		va_list vars;
		va_start(vars,paraformat);
		paranum = strlen(paraformat);
		for(int i = 0; i < paranum; ++i)
		{
			char * t = paraformat + i * sizeof(char);
			switch(*t)
			{
			case 'i':
				{
					lua_Number para = va_arg(vars,int);
					lua_pushnumber(se->m_L, para);
					break;
				}
			case 'f':
				{
				lua_Number para = va_arg(vars,float);
				lua_pushnumber(se->m_L, para);
				break;
				}
			case 'd':
				{
					lua_Number para = va_arg(vars,double);
					lua_pushnumber(se->m_L, para);
					break;
				}
			case 'b':
				{
					int para = va_arg(vars,bool);
					lua_pushboolean(se->m_L, para);
					break;
				}
			case 's':
				{
					char* para = va_arg(vars,char*);
					lua_pushstring(se->m_L, para);
					break;
				}
			}
		}
	}
	if(lua_pcall(se->m_L, paranum, 0, 0))
	{
		printf("Call script func \'%s\' error!\n",funcname);
		return false;
	}
	return true;
}

bool RegCFuncForScript(const ScriptEntity *se, Scripted_CFunction  func, const char * funcrefername)
{
	if(se == 0 || se->m_L == 0|| func == 0|| funcrefername == 0)
		return false;
	lua_pushcfunction(se->m_L, func);
	lua_setglobal(se->m_L,funcrefername);
	return true;
}

void OutputErrorCallInfo(char * funcname, int idx, char *tname)
{
	printf("%s para %d must be a %s \n",funcname, idx, tname);
}